﻿Imports System.ComponentModel
Imports System.Web.UI
Imports System.Web.UI.HtmlControls
Imports System.Web.UI.WebControls
Imports System.Web.UI.Design.WebControls
Imports System.Text
Imports System.IO
Imports System.Drawing
Imports System.Web
Imports System.Runtime.Serialization
Imports System.Data.SqlClient
Imports System.ComponentModel.Design
Imports System.Drawing.Design



Public Class ProveedorDatosServidor
  Inherits ScriptControl
  Private WebMethodValor As String = ""
  ''' <summary>
  ''' Nombre del WebMethod al cual llama para obtener los registros.
  ''' </summary>
  ''' <value></value>
  ''' <returns></returns>
  ''' <remarks></remarks>
  <Description("Nombre del WebMethod al cual llama para obtener los registros.")> _
  Public Property WebMethod() As String
    Get
      Return WebMethodValor
    End Get
    Set(ByVal value As String)
      WebMethodValor = value
    End Set
  End Property

  Dim EncontradoValor As String = ""
  ''' <summary>
  ''' Función Javascript que se ejecutará una vez encontrado un registro.
  ''' </summary>
  ''' <value></value>
  ''' <returns></returns>
  ''' <remarks></remarks>
  <Description("Función Javascript que se ejecutará una vez encontrado un registro.")> _
  Public Property Encontrado() As String
    Get
      Return EncontradoValor
    End Get
    Set(ByVal value As String)
      EncontradoValor = value
    End Set
  End Property

  Dim ActualizadoValor As String = ""
  ''' <summary>
  ''' Función Javascript que se ejecutará una vez Actualizados los datos en el Servidor.
  ''' </summary>
  ''' <value></value>
  ''' <returns></returns>
  ''' <remarks></remarks>
  <Description("Función Javascript que se ejecutará una vez actualizados los datos en el Servidor.")> _
  Public Property Actualizado() As String
    Get
      Return ActualizadoValor
    End Get
    Set(ByVal value As String)
      ActualizadoValor = value
    End Set
  End Property

  Dim AgregadoValor As String = ""
  ''' <summary>
  ''' Función Javascript que se ejecutará una vez agregado el registro en el Servidor.
  ''' </summary>
  ''' <value></value>
  ''' <returns></returns>
  ''' <remarks></remarks>
  <Description("Función Javascript que se ejecutará una vez agregado el registro en el Servidor.")> _
  Public Property Agregado() As String
    Get
      Return AgregadoValor
    End Get
    Set(ByVal value As String)
      AgregadoValor = value
    End Set
  End Property

  Dim ModificadoValor As String = ""
  ''' <summary>
  ''' Función Javascript que se ejecutará una vez modificado el registro en el Servidor.
  ''' </summary>
  ''' <value></value>
  ''' <returns></returns>
  ''' <remarks></remarks>
  <Description("Función Javascript que se ejecutará una vez modificado el registro en el Servidor.")> _
  Public Property Modificado() As String
    Get
      Return ModificadoValor
    End Get
    Set(ByVal value As String)
      ModificadoValor = value
    End Set
  End Property

  Dim EliminadoValor As String = ""
  ''' <summary>
  ''' Función Javascript que se ejecutará una vez eliminado el registro en el Servidor.
  ''' </summary>
  ''' <value></value>
  ''' <returns></returns>
  ''' <remarks></remarks>
  <Description("Función Javascript que se ejecutará una vez eliminado el registro en el Servidor.")> _
  Public Property Eliminado() As String
    Get
      Return EliminadoValor
    End Get
    Set(ByVal value As String)
      EliminadoValor = value
    End Set
  End Property

  Dim FinDeArchivoValor As String = ""
  ''' <summary>
  ''' Función Javascript que se ejecutará cuando la busqueda supere el fondo de la tabla.
  ''' </summary>
  ''' <value></value>
  ''' <returns></returns>
  ''' <remarks></remarks>
  <Description("Función Javascript que se ejecutará cuando la busqueda supere el fondo de la tabla.")> _
  Public Property FinDeArchivo() As String
    Get
      Return FinDeArchivoValor
    End Get
    Set(ByVal value As String)
      FinDeArchivoValor = value
    End Set
  End Property

  Dim PrincipioDeArchivoValor As String = ""
  ''' <summary>
  ''' Función Javascript que se ejecutará cuando la busqueda supere el tope de la tabla.
  ''' </summary>
  ''' <value></value>
  ''' <returns></returns>
  ''' <remarks></remarks>
  <Description("Función Javascript que se ejecutará cuando la busqueda supere el tope de la tabla.")> _
  Public Property PrincipioDeArchivo() As String
    Get
      Return PrincipioDeArchivoValor
    End Get
    Set(ByVal value As String)
      PrincipioDeArchivoValor = value
    End Set
  End Property

  Dim OrdenesValor As List(Of OrdenDatos) = New List(Of OrdenDatos)
  ''' <summary>
  ''' Lista de campos por los cuales se van a ordenar los datos.
  ''' </summary>
  ''' <value></value>
  ''' <returns></returns>
  ''' <remarks></remarks>
  <Description("Lista de campos por los cuales se van a ordenar los datos.")> _
  <Editor(GetType(DatosOrdenesCollectionEditor), GetType(UITypeEditor)), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), PersistenceMode(PersistenceMode.InnerProperty)> _
  Public ReadOnly Property Ordenes() As List(Of OrdenDatos)
    Get
      Return OrdenesValor
    End Get
  End Property
  ''' <summary>
  ''' Valores por defecto de cada campo
  ''' </summary>
  ''' <remarks></remarks>
  Dim DefectosValor As List(Of DefectoDatos) = New List(Of DefectoDatos)
  <Description("Valores por defecto de cada campo.")> _
  <Editor(GetType(DatosDefectoCollectionEditor), GetType(UITypeEditor)), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), PersistenceMode(PersistenceMode.InnerProperty)> _
  Public ReadOnly Property Defectos() As List(Of DefectoDatos)
    Get
      Return DefectosValor
    End Get
  End Property

  Dim AsincronicoValor As Boolean = True
  ''' <summary>
  ''' Indica si la comunicacion con el servidor se realizara de forma sincrónica o asincrónica, por defecto es Asincrónica
  ''' </summary>
  ''' <value></value>
  ''' <returns></returns>
  ''' <remarks></remarks>
  <Description("Indica si la comunicacion con el servidor se realizara de forma sincrónica o asincrónica, por defecto es Asincrónica.")> _
  Public Property Asincronico() As Boolean
    Get
      Return AsincronicoValor
    End Get
    Set(ByVal value As Boolean)
      AsincronicoValor = value
    End Set
  End Property

  Dim RESTValor As Boolean = False
  ''' <summary>
  ''' Indica si la comunicacion con el servidor se realizara en modo RESTful, por defecto es false.
  ''' </summary>
  ''' <value></value>
  ''' <returns></returns>
  ''' <remarks></remarks>
  <Description("Indica si la comunicacion con el servidor se realizara en modo REST, por defecto es false.")> _
  Public Property REST() As Boolean
    Get
      Return RESTValor
    End Get
    Set(ByVal value As Boolean)
      RESTValor = value
    End Set
  End Property
  Dim ODataValor As Boolean = False
  ''' <summary>
  ''' Indica si la comunicacion con el servidor se realizara en modo RESTful, por defecto es false.
  ''' </summary>
  ''' <value></value>
  ''' <returns></returns>
  ''' <remarks></remarks>
  <Description("Indica si la comunicacion con el servidor se realizara en modo OData, por defecto es false.")> _
  Public Property OData() As Boolean
    Get
      Return ODataValor
    End Get
    Set(ByVal value As Boolean)
      ODataValor = value
    End Set
  End Property
  Dim ModeloValor As String = String.Empty
  ''' <summary>
  ''' Nombre de la clase Modelo en caso de REST = true.
  ''' </summary>
  ''' <value></value>
  ''' <returns></returns>
  ''' <remarks></remarks>
  <Description("Nombre de la clase Modelo en caso de REST = true.")> _
  Public Property Modelo() As String
    Get
      Return ModeloValor
    End Get
    Set(ByVal value As String)
      ModeloValor = value
    End Set
  End Property


  Dim ErradoValor As String = ""
  ''' <summary>
  ''' Función Javascript que se ejecutará en caso de error en el servidor.
  ''' </summary>
  ''' <value></value>
  ''' <returns></returns>
  ''' <remarks></remarks>
  <Description("Función Javascript que se ejecutará en caso de error en el servidor.")> _
  Public Property Errado() As String
    Get
      Return ErradoValor
    End Get
    Set(ByVal value As String)
      ErradoValor = value
    End Set
  End Property

  Dim FiltroValor As String = ""
  ''' <summary>
  ''' Parametro de filtrado de registros para evealuar en el servidor.
  ''' </summary>
  ''' <value></value>
  ''' <returns></returns>
  ''' <remarks></remarks>
  <Description("Parametro de filtrado de registros para evealuar en el servidor.")> _
  Public Property Filtro() As String
    Get
      Return FiltroValor
    End Get
    Set(ByVal value As String)
      FiltroValor = value
    End Set
  End Property

  Dim ExpandValor As String = ""
  ''' <summary>
  ''' Parametro de filtrado de registros para evealuar en el servidor.
  ''' </summary>
  ''' <value></value>
  ''' <returns></returns>
  ''' <remarks></remarks>
  <Description("Parametro de join de registros para evealuar en el servidor.")> _
  Public Property Expand() As String
    Get
      Return ExpandValor
    End Get
    Set(ByVal value As String)
      ExpandValor = value
    End Set
  End Property


  Dim ExpandUpdateValor As String = ""
  ''' <summary>
  ''' Parametro de filtrado de registros para evealuar en el servidor.
  ''' </summary>
  ''' <value></value>
  ''' <returns></returns>
  ''' <remarks></remarks>
  <Description("Lista propiedades extendidas separadas por coma que viajan al servidor en el POST y PUT")> _
  Public Property ExpandUpdate() As String
    Get
      Return ExpandUpdateValor
    End Get
    Set(ByVal value As String)
      ExpandUpdateValor = value
    End Set
  End Property


  Dim SelectValor As String = ""
  ''' <summary>
  ''' Parametro de filtrado de registros para evealuar en el servidor.
  ''' </summary>
  ''' <value></value>
  ''' <returns></returns>
  ''' <remarks></remarks>
  <Description("Parametro de Select de registros para evealuar en el servidor.")> _
  Public Property [Select]() As String
    Get
      Return SelectValor
    End Get
    Set(ByVal value As String)
      SelectValor = value
    End Set
  End Property

  Dim InlineCountValor As Boolean = False
  ''' <summary>
  ''' cantidad de registros en el entidad (corresponde a InlineCount de ODATA).
  ''' </summary>
  ''' <value></value>
  ''' <returns></returns>
  ''' <remarks></remarks>
  <Description("cantidad de registros en el entidad (corresponde a InlineCount de ODATA).")> _
  Public Property InlineCount() As Boolean
    Get
      Return InlineCountValor
    End Get
    Set(ByVal value As Boolean)
      InlineCountValor = value
    End Set
  End Property

  Dim OrdenDefectoValor As String = ""
  ''' <summary>
  ''' Parametro de filtrado de registros para evealuar en el servidor.
  ''' </summary>
  ''' <value></value>
  ''' <returns></returns>
  ''' <remarks></remarks>
  <Description("Orden en el que inicia el proveedor")> _
  Public Property OrdenDefecto() As String
    Get
      Return OrdenDefectoValor
    End Get
    Set(ByVal value As String)
      OrdenDefectoValor = value
    End Set
  End Property

  Dim IndependienteValor As Boolean = False
  ''' <summary>
  ''' "Indica si el repositorio en el cliente es independiente de otros con el mismo webmethod"
  ''' </summary>
  ''' <value></value>
  ''' <returns></returns>
  ''' <remarks></remarks>
  <Description("Indica si el repositorio en el cliente es independiente de otros con el mismo webmethod")> _
  Public Property Independiente() As Boolean
    Get
      Return IndependienteValor
    End Get
    Set(ByVal value As Boolean)
      IndependienteValor = value
    End Set
  End Property


  Dim DatoRaizValor As String = "value"
  ''' <summary>
  ''' "Indica cual es la propiedad que dará valor al proveedor de datos (solo OData)"
  ''' </summary>
  ''' <value>por defecto es value</value>
  ''' <returns></returns>
  ''' <remarks></remarks>
  <Description("Indica cual es la propiedad que dará valor al proveedor de datos (solo OData)")> _
  Public Property DatoRaiz() As String
    Get
      Return DatoRaizValor
    End Get
    Set(ByVal value As String)
      DatoRaizValor = value
    End Set
  End Property

  Dim ODVersionValor As Integer = 3
  ''' <summary>
  ''' "Indica la version de OData que se esta usando"
  ''' </summary>
  ''' <value>por defecto es 3</value>
  ''' <returns></returns>
  ''' <remarks></remarks>
  <Description("Indica la version de OData que se esta usando")> _
  Public Property ODVersion() As Integer
    Get
      Return ODVersionValor
    End Get
    Set(ByVal value As Integer)
      ODVersionValor = value
    End Set
  End Property

  Dim TopValor As String = String.Empty
  ''' <summary>
  ''' "corresponde a $top de OData"
  ''' </summary>
  ''' <value>por defecto es string vacio</value>
  ''' <returns></returns>
  ''' <remarks></remarks>
  <Description("corresponde a $top de OData")> _
  Public Property Top() As String
    Get
      Return TopValor
    End Get
    Set(ByVal value As String)
      TopValor = value
    End Set
  End Property


  Private Sub ActualizarModelo(ByRef pModelo As Dictionary(Of String, String), ByVal pNombrePadre As String, ByVal pTipo As Type)
    For Each SubProp In pTipo.GetProperties
      If SubProp.PropertyType.IsSerializable Then
        pModelo.Add(pNombrePadre + "__" + SubProp.Name, SubProp.PropertyType.FullName.Split(",")(0).Split(".").Last)
      Else
        Dim NombrePadre = pNombrePadre + "__" + SubProp.Name
        Dim TipoPadre As Type = SubProp.PropertyType
        Me.ActualizarModelo(pModelo, NombrePadre, TipoPadre)
      End If
    Next
  End Sub


  Protected Overrides Function GetScriptDescriptors() As IEnumerable(Of ScriptDescriptor)
    Dim descriptor As New ScriptControlDescriptor("MoniMisi2.ProveedorDatosServidor", Me.ClientID)
    Dim descriptors As New List(Of ScriptDescriptor)
    Dim Model As New Dictionary(Of String, String)

    Dim Tipo As Type = Type.GetType(Modelo, False, True)
    If Not Tipo Is Nothing Then
      For Each Prop In Tipo.GetProperties
        If Prop.PropertyType.IsSerializable Then
          Model.Add(Prop.Name, Prop.PropertyType.FullName.Split(",")(0).Split(".").Last)
                    If Me.REST Or Me.OData Then
                        If Prop.GetCustomAttributes(GetType(DefaultValueAttribute), False).Length > 0 Then
                            Me.Defectos.Add(New DefectoDatos(Prop.Name, Prop.GetCustomAttributes(GetType(DefaultValueAttribute), False)(0).value))
                        End If
                        Dim TipoValor = Nothing
                        TipoValor = Tipo.InvokeMember("new", Reflection.BindingFlags.CreateInstance, Nothing, TipoValor, Nothing)
                        Dim Valor = Prop.GetValue(TipoValor, Nothing)
                        If Not Valor Is Nothing Then
                            Me.Defectos.Add(New DefectoDatos(Prop.Name, Valor))
                        End If
                    End If
        Else
          Dim NombrePadre = Prop.Name
          Dim TipoPadre As Type = Prop.PropertyType
          Me.ActualizarModelo(Model, NombrePadre, TipoPadre)
          'For Each SubProp In TipoPadre.GetProperties
          '  If SubProp.PropertyType.IsSerializable Then
          '    Model.Add(NombrePadre + "__" + SubProp.Name, SubProp.PropertyType.FullName.Split(",")(0).Split(".").Last)
          '  End If
          'Next
        End If
      Next
    End If
    descriptor.AddProperty("WebMethod", IIf(Me.WebMethod = "", "Manejo" + Me.ClientID, Me.WebMethod))
    descriptor.AddProperty("Independiente", Me.Independiente)
    descriptor.AddProperty("Ordenes", Me.Ordenes)
    descriptor.AddProperty("Defectos", Me.Defectos)
    descriptor.AddProperty("Asincronico", Me.Asincronico)
    descriptor.AddProperty("REST", Me.REST Or Me.OData)
    descriptor.AddProperty("OData", Me.OData)
    descriptor.AddProperty("InlineCount", Me.InlineCount)
    descriptor.AddProperty("ODVersion", Me.ODVersion)

    descriptor.AddProperty("Modelo", Model)
    descriptor.AddProperty("DatoRaiz", Me.DatoRaiz)
    If Me.OrdenDefecto <> String.Empty Then
      descriptor.AddProperty("OrdenDefecto", Me.OrdenDefecto)
    End If

    If Me.Filtro <> String.Empty Then
      descriptor.AddProperty("Filtro", Me.Filtro)
    End If
    If Me.Expand <> String.Empty Then
      descriptor.AddProperty("Expand", Me.Expand)
    End If
    If Me.ExpandUpdate <> String.Empty Then
      descriptor.AddProperty("ExpandUpdate", Me.ExpandUpdate)
    End If
    If Me.Select <> String.Empty Then
      descriptor.AddProperty("Select", Me.Select)
    End If
    If Me.Top <> String.Empty Then
      descriptor.AddProperty("Top", Me.Top)
    End If
    If Me.Encontrado <> String.Empty Then
      descriptor.AddEvent("Encontrado", Me.Encontrado)
    End If
    If Me.Errado <> String.Empty Then
      descriptor.AddEvent("Errado", Me.Errado)
    End If
    If Me.Actualizado <> String.Empty Then
      descriptor.AddEvent("Actualizado", Me.Actualizado)
    End If
    If Me.Agregado <> String.Empty Then
      descriptor.AddEvent("Agregado", Me.Agregado)
    End If
    If Me.Modificado <> String.Empty Then
      descriptor.AddEvent("Modificado", Me.Modificado)
    End If
    If Me.Eliminado <> String.Empty Then
      descriptor.AddEvent("Eliminado", Me.Eliminado)
    End If

    If Me.PrincipioDeArchivo <> String.Empty Then
      descriptor.AddEvent("Principio", Me.PrincipioDeArchivo)
    End If
    If Me.FinDeArchivo <> String.Empty Then
      descriptor.AddEvent("Fin", Me.FinDeArchivo)
    End If
    descriptors.Add(descriptor)
    Return descriptors
  End Function

  Protected Overrides Function GetScriptReferences() As IEnumerable(Of ScriptReference)
    Dim scriptRef As New ScriptReference("MoniMisi2.ProveedorDatosServidor.js", Funciones.NombreCompletoEnsamblado(Me.GetType, "MoniMisi2.ProveedorDatosServidor"))
    scriptRef.NotifyScriptLoaded = False
    Dim scriptRefs As New List(Of ScriptReference)
    scriptRefs.Add(scriptRef)
    Return scriptRefs
  End Function

  Public Overloads Shared Function LeerFilas(ByVal pContrato As ProveedorDatosServidor.Contrato, ByVal pDatos As List(Of Object)) As ProveedorDatosServidor.Contrato
    Try
      Dim Indice As New List(Of Indice)
      Indice.Add(New Indice("", ""))
      Dim PaginaActual As Integer = -1
      pContrato.Estructura = New Dictionary(Of String, String)
      If pDatos.Count > 0 Then
        Dim Tipo As System.Type = pDatos(0).GetType()
        For Each Campo As Reflection.FieldInfo In Tipo.GetFields()
          pContrato.Estructura.Add(Campo.Name, Campo.FieldType.Name)
        Next
      Else
        pContrato.Metodo.Nombre = ""
      End If
      Indice(0).P = pDatos
      pContrato.Indice = Indice
    Catch ex As Exception
      Throw ex
    End Try
    Return pContrato
  End Function
  Public Overloads Shared Function LeerFilas(ByVal pContrato As ProveedorDatosServidor.Contrato, ByVal pDatos As DataRow()) As ProveedorDatosServidor.Contrato
    Try
      Dim Indice As New List(Of Indice)
      Indice.Add(New Indice("", ""))
      Dim Pagina As New List(Of Dictionary(Of String, Object))
      Dim PaginaActual As Integer = -1
      pContrato.Estructura = New Dictionary(Of String, String)
      If pDatos.Length > 0 Then
        For Each Columna As DataColumn In pDatos(0).Table.Columns
          pContrato.Estructura.Add(Columna.ColumnName, Columna.DataType.Name)
        Next

        For Each FilaDato As DataRow In pDatos
          Dim Fila As New Dictionary(Of String, Object)
          For Each Colu As DataColumn In pDatos(0).Table.Columns
            Fila.Add(Colu.ColumnName, FilaDato.Item(Colu.ColumnName))
          Next
          Pagina.Add(Fila)
        Next
      End If
      If Pagina.Count = 0 Then
        pContrato.Metodo.Nombre = ""
      End If
      Indice(0).P = Pagina
      pContrato.Indice = Indice
    Catch ex As Exception
      Throw ex
    End Try
    Return pContrato
  End Function
  Public Overloads Shared Function LeerFilas(ByVal pContrato As ProveedorDatosServidor.Contrato, ByVal pDatos As DataTable) As ProveedorDatosServidor.Contrato
    Try
      Dim Indice As New List(Of Indice)
      Indice.Add(New Indice("", ""))
      Dim Pagina As New List(Of Dictionary(Of String, Object))
      Dim PaginaActual As Integer = -1
      pContrato.Estructura = New Dictionary(Of String, String)
      For Each Columna As DataColumn In pDatos.Columns
        pContrato.Estructura.Add(Columna.ColumnName, Columna.DataType.Name)
      Next

      For Each FilaDato As DataRow In pDatos.Rows
        Dim Fila As New Dictionary(Of String, Object)
        For Each Colu As DataColumn In pDatos.Columns
          Fila.Add(Colu.ColumnName, FilaDato.Item(Colu.ColumnName))
        Next
        Pagina.Add(Fila)
      Next
      If Pagina.Count = 0 Then
        pContrato.Metodo.Nombre = ""
      End If
      Indice(0).P = Pagina
      pContrato.Indice = Indice
    Catch ex As Exception
      Throw ex
    End Try
    Return pContrato
  End Function
  Public Overloads Shared Function LeerFilas(ByVal pContrato As ProveedorDatosServidor.Contrato, ByVal pDatos As SqlDataAdapter) As ProveedorDatosServidor.Contrato
    Try
      Dim Indice As New List(Of Indice)
      Indice.Add(New Indice("", ""))
      Dim Pagina As New List(Of Dictionary(Of String, Object))
      Dim PaginaActual As Integer = -1
      Dim Adaptador As SqlDataAdapter = pDatos
      Dim Conexion As SqlConnection = Adaptador.SelectCommand.Connection()
      Conexion.Open()
      Dim ReaderPagina As SqlDataReader = Adaptador.SelectCommand.ExecuteReader()
      pContrato.Estructura = New Dictionary(Of String, String)
      For Each Fila As DataRow In ReaderPagina.GetSchemaTable.Rows
        pContrato.Estructura.Add(Fila.Item("ColumnName"), Fila.Item("DataType").name)
      Next
      Do While ReaderPagina.Read()
        Dim Fila As New Dictionary(Of String, Object)
        For Colu = 0 To ReaderPagina.FieldCount - 1
          Fila.Add(ReaderPagina.GetName(Colu), ReaderPagina.GetValue(Colu))
        Next
        Pagina.Add(Fila)
      Loop
      Conexion.Close()
      If Pagina.Count = 0 Then
        pContrato.Metodo.Nombre = ""
      End If
      Indice(0).P = Pagina
      pContrato.Indice = Indice
    Catch ex As Exception
      Throw ex
    End Try
    Return pContrato
  End Function
  Public Shared Function LeerFilasPaginadas(ByVal pContrato As ProveedorDatosServidor.Contrato, ByVal pDatos As SqlDataAdapter, ByVal pIndice As SqlDataAdapter, Optional ByVal pIDCacheIndice As String = "") As ProveedorDatosServidor.Contrato
    Try
      Dim Indice As New List(Of ProveedorDatosServidor.Indice)
      Dim Pagina As New List(Of Dictionary(Of String, Object))
      Dim PaginaActual As Integer = -1
      Dim LimiteSuperior As String = ""
      Dim LimiteInferior As String = ""
      If pContrato.Metodo.Accion.Contains("I") Then '' Busco Indice
        Dim LeerDeDisco As Boolean = True
        If pIDCacheIndice <> "" Then
          If Not HttpContext.Current.Application(pIDCacheIndice) Is Nothing Then
            LeerDeDisco = False
            Indice = HttpContext.Current.Application(pIDCacheIndice)
          End If
        End If
        If LeerDeDisco Then
          Dim Adaptador As SqlDataAdapter = pIndice
          Dim Conexion As SqlConnection = Adaptador.SelectCommand.Connection()
          Conexion.Open()
          Dim ReaderPaginas As SqlDataReader = Adaptador.SelectCommand.ExecuteReader()
          Do While ReaderPaginas.Read()
            Dim Valor = ReaderPaginas.GetValue(1)
            If IsDBNull(Valor) Then
              Valor = ""
            End If
            Indice.Add(New ProveedorDatosServidor.Indice(Valor, ""))
          Loop
          Conexion.Close()
          If pIDCacheIndice <> "" Then
            HttpContext.Current.Application.Add(pIDCacheIndice, Indice)
          End If
        End If
        If Not pContrato.Clave Is Nothing Then '' Si esta buscando un registro en particular identifico en que pagina esta
          Dim Mitad = 1
          Dim MenorValor = 0
          Dim MayorValor = Indice.Count - 1
          Dim ValorEncontrado = ""
          Do While Mitad > 0
            Mitad = Math.Round((MayorValor - MenorValor) / 2)
            ValorEncontrado = Indice(MenorValor + Mitad).C.ToUpper
            If pContrato.Clave > ValorEncontrado Then
              MenorValor = MenorValor + Mitad
            Else
              MayorValor = MayorValor - Mitad
            End If
          Loop
          PaginaActual = MenorValor
          If pContrato.Clave > Indice(MayorValor).C Then
            PaginaActual = PaginaActual + 1
          End If
          If PaginaActual = 0 Then
            LimiteSuperior = Nothing
          Else
            LimiteSuperior = Indice(PaginaActual).C
          End If
          If PaginaActual + 1 = Indice.Count Then
            LimiteInferior = Nothing
          Else
            LimiteInferior = Indice(PaginaActual + 1).C
          End If
        Else
          Select Case pContrato.Operacion.Valor
            Case -1 '' Ultima Pagina
              LimiteSuperior = Indice.Last.C
              LimiteInferior = Nothing
              PaginaActual = Indice.Count - 1
            Case 0 '' Primera Pagina
              LimiteSuperior = Nothing
              LimiteInferior = Indice(1).C
              PaginaActual = 0
            Case Else
              LimiteSuperior = Indice(pContrato.Operacion.Valor).C
              LimiteInferior = Indice(pContrato.Operacion.Valor + 1).C
              PaginaActual = pContrato.Operacion.Valor
          End Select

        End If
      Else
        LimiteSuperior = pContrato.Desde
        LimiteInferior = pContrato.Hasta
        PaginaActual = -1
      End If

      If pContrato.Metodo.Accion.Contains("P") Then '' Busco Pagina
        Dim Adaptador As SqlDataAdapter = pDatos
        If Not LimiteSuperior Is Nothing Then
          pDatos.SelectCommand.Parameters(0).Value = LimiteSuperior
        End If
        If Not LimiteInferior Is Nothing Then
          pDatos.SelectCommand.Parameters(1).Value = LimiteInferior
        End If

        Dim Conexion As SqlConnection = Adaptador.SelectCommand.Connection()
        Conexion.Open()
        Dim ReaderPagina As SqlDataReader = Adaptador.SelectCommand.ExecuteReader()
        pContrato.Estructura = New Dictionary(Of String, String)
        For Each Fila As DataRow In ReaderPagina.GetSchemaTable.Rows
          pContrato.Estructura.Add(Fila.Item("ColumnName"), Fila.Item("DataType").name)
        Next
        Do While ReaderPagina.Read()
          Dim Fila As New Dictionary(Of String, Object)
          For Colu = 0 To ReaderPagina.FieldCount - 1
            Fila.Add(ReaderPagina.GetName(Colu), ReaderPagina.GetValue(Colu))
          Next
          Pagina.Add(Fila)
        Loop
        Conexion.Close()
        If Pagina.Count = 0 Then
          pContrato.Metodo.Nombre = ""
        End If
        If pContrato.Metodo.Accion.Contains("I") Then
          Indice(PaginaActual).P = Pagina
        End If
      End If
      If pContrato.Metodo.Accion.Contains("I") Then
        pContrato.Indice = Indice
      End If
      If pContrato.Metodo.Accion = "P" Then
        pContrato.Pagina = Pagina
      End If
    Catch ex As Exception
      Throw ex
    End Try
    Return pContrato
  End Function


  <DataContract()> _
  Public Class Metodo
    <DataMember()> _
    Public Accion As String
    <DataMember()> _
    Public Nombre As String
    <DataMember()> _
    Public Parametros As Object
  End Class

  <DataContract()> _
  Public Class Contrato
    Public Sub New()
      MyBase.New()
    End Sub

    <DataMember()> _
    Public Estructura As Dictionary(Of String, String)
    <DataMember()> _
    Public Metodo As Metodo
    <DataMember()> _
    Public Orden As Object
    <DataMember()> _
    Public Desde As Object
    <DataMember()> _
    Public Hasta As Object
    <DataMember()> _
    Public Clave As Object
    <DataMember()> _
    Public Operacion As Operacion
    <DataMember()> _
    Public Filtro As String

    Public Indice As Object
    Public Pagina As Object

  End Class

  Public Class Indice
    Public Sub New(ByVal pC As Object, ByVal pP As Object)
      C = pC
      P = pP
    End Sub
    Public C As Object
    Public P As Object
  End Class

  Public Class Operacion
    Public Nombre As String
    Public Valor As Object
  End Class


End Class

Public Class ProveeedorDatosException
  Inherits Exception
  Public Sub New(ByVal pMensaje As String)
    MyBase.New("d:['" + pMensaje + "']")
  End Sub
  Public Sub New(ByVal pMensajes As List(Of String))
    MyBase.New(ListaAString(pMensajes))
  End Sub
  Public Shared Function ListaAString(ByVal pMensajes As List(Of String)) As String
    Dim Mensaje As String = "d:["
    For Each Men In pMensajes
      Mensaje += "'" + Men + "'" + ","
    Next
    Mensaje = Mensaje.Substring(0, Mensaje.Length - 1) + "]"
    Return Mensaje
  End Function
End Class
Public Class OrdenDatos
  Private ColumnaValor As String = String.Empty
  Public Property Columna() As String
    Get
      Return ColumnaValor
    End Get
    Set(ByVal value As String)
      ColumnaValor = value
    End Set
  End Property
End Class

Public Class DefectoDatos
  Public Sub New(ByVal pColumna As String, ByVal pValor As Object)
    ColumnaValor = pColumna
    Valor = pValor
  End Sub
  Private ColumnaValor As String = String.Empty
  Public Property Columna() As String
    Get
      Return ColumnaValor
    End Get
    Set(ByVal value As String)
      ColumnaValor = value
    End Set
  End Property
  Private ValorValor As Object = ""
  Public Property Valor() As Object
    Get
      Return ValorValor
    End Get
    Set(ByVal value As Object)
      ValorValor = value
    End Set
  End Property
End Class

Public Class DatosOrdenesCollectionEditor
  Inherits CollectionEditor

  Public Sub New(ByVal newType As Type)
    MyBase.New(newType)
  End Sub

  Protected Overrides Function CanSelectMultipleInstances() As Boolean
    Return False
  End Function

  Protected Overrides Function CreateCollectionItemType() As Type
    Return GetType(OrdenDatos)
  End Function

End Class
Public Class DatosDefectoCollectionEditor
  Inherits CollectionEditor

  Public Sub New(ByVal newType As Type)
    MyBase.New(newType)
  End Sub

  Protected Overrides Function CanSelectMultipleInstances() As Boolean
    Return False
  End Function

  Protected Overrides Function CreateCollectionItemType() As Type
    Return GetType(DefectoDatos)
  End Function

End Class